/*
 * @(#)CodedElementTransformer.java
 * Date 2013-04-10
 * Version 1.0
 * Author Jim Horner
 * Copyright (c)2012
 */


package us.hornerscorners.lamppost.registry.transformer.model;

import java.util.ArrayList;
import java.util.List;

import javax.enterprise.context.ApplicationScoped;

import javax.inject.Inject;

import oasis.names.tc.ebxml_regrep.xsd.rim._3.ClassificationType;
import oasis.names.tc.ebxml_regrep.xsd.rim._3.SlotType1;

import org.apache.commons.lang3.StringUtils;

import us.hornerscorners.lamppost.exception.ConversionException;
import us.hornerscorners.lamppost.exception.ServiceActionError;
import us.hornerscorners.lamppost.exception.SeverityType;
import us.hornerscorners.lamppost.exception.ValidationException;

import us.hornerscorners.lamppost.model.common.CodedElement;

import us.hornerscorners.lamppost.registry.constant.AvailabilityStatus;
import us.hornerscorners.lamppost.registry.constant.ErrorCode;
import us.hornerscorners.lamppost.registry.constant.Metadata;
import us.hornerscorners.lamppost.registry.constant.QuerySlotName;
import us.hornerscorners.lamppost.registry.constant.SlotName;

import us.hornerscorners.lamppost.registry.utils.XDSUtils;

import us.hornerscorners.lamppost.transformer.AbstractTransformer;


/**
 *
 * @author jim
 */
@ApplicationScoped
public class CodedElementTransformer
        extends AbstractTransformer<ClassificationType, CodedElement> {

    /** Field description */
    @Inject
    private LocalizedStringTransformer localizedStringTransformer;

    /**
     * Method description
     *
     *
     * @param status
     *
     * @return
     */
    public CodedElement transform(AvailabilityStatus status) {

        CodedElement result = null;

        if (status != null) {

            result = new CodedElement();
            result.setCode(status.getCode());
            result.setCodeSystem(Metadata.ClassificationStatusType.getURN());
            result.setCodeSystemName(Metadata.ClassificationStatusType.getURN());
        }

        return result;
    }

    /**
     * Method description
     *
     *
     * @param ctype
     *
     * @return
     */
    @Override
    public CodedElement transform(ClassificationType ctype) throws ValidationException {

        List<ServiceActionError> errors = new ArrayList<>();

        CodedElement result = new CodedElement();

        result.setEntryURN(XDSUtils.assignEntryUUID(ctype.getId()));

        // versioning
        result.setEntryLogicalURN(StringUtils.defaultIfBlank(ctype.getLid(),
                result.getEntryURN()));
        result.setEntryVersion(
            StringUtils.defaultIfBlank(
                XDSUtils.parseVersionName(ctype.getVersionInfo()), "1"));

        result.getDisplayNames().addAll(
            this.localizedStringTransformer.transform(ctype.getName()));
        result.getDescriptions().addAll(
            this.localizedStringTransformer.transform(ctype.getDescription()));

        result.setCode(ctype.getNodeRepresentation());

        // find codingScheme
        String codingScheme = SlotName.CodingScheme.getCode();

        for (SlotType1 slot : ctype.getSlot()) {

            if (codingScheme.equals(slot.getName())) {

                String codeName = XDSUtils.parseFirstValue(slot);

                // TODO look for translation from name to OID
                // e.g. LOINC -> 2.16.840.1.113883.6.1
                result.setCodeSystem(codeName);
                result.setCodeSystemName(codeName);

                break;
            }
        }

        if (StringUtils.isBlank(result.getCodeSystem())) {

            String msg =
                String.format(
                    "Classification [%s] is missing required codingScheme slot.",
                    ctype.getId());

            ServiceActionError error =
                new ServiceActionError(ErrorCode.XDSRegistryMetadataError.getCode(), msg,
                                       SeverityType.Error);

            errors.add(error);
        }

        if (errors.isEmpty() == false) {

            throw new ValidationException(getErrorLocation(), errors);
        }

        return result;
    }

    /**
     * Method description
     *
     *
     * @param queryString
     *
     * @return
     */
    public CodedElement transform(QuerySlotName slotName, String queryString)
            throws ConversionException {

        CodedElement result = null;

        if (StringUtils.isNotBlank(queryString)) {

            String[] arr = StringUtils.splitPreserveAllTokens(queryString, "^");

            if ((arr != null) && (arr.length > 0)) {

                result = new CodedElement();
                result.setCode(arr[0]);

                if (arr.length > 2) {

                    result.setCodeSystem(arr[2]);
                    result.setCodeSystemName(arr[2]);
                }
            }
        }

        if (StringUtils.isNotBlank(queryString) && (result == null)) {

            String msg =
                String.format("Slot [%s] value [%s] is not a valid coded element.",
                              slotName.getCode(), queryString);
            ServiceActionError error =
                new ServiceActionError(ErrorCode.XDSRegistryMetadataError.getCode(), msg,
                                       SeverityType.Error);

            throw new ConversionException(getClass(), error);
        }

        return result;
    }
}
